package com.jacky.grpc.serivces;

import com.jacky.grpc.proto.HelloReply;
import com.jacky.grpc.proto.HelloRequest;
import com.jacky.grpc.proto.SimpleGrpc;
import io.grpc.Grpc;
import io.grpc.stub.StreamObserver;
import net.devh.boot.grpc.client.inject.GrpcClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import java.util.Iterator;

@Service
public class ClientService {

    private static final Logger LOGGER = LoggerFactory.getLogger(ClientService.class);

    @GrpcClient("greetingsService")
    private SimpleGrpc.SimpleBlockingStub blockingStub;

    @GrpcClient("greetingsService")
    private SimpleGrpc.SimpleStub simpleStub;

    public void sayHello() {
        HelloRequest req = HelloRequest.newBuilder().setName("Jack").build();

        // 阻塞API
        HelloReply reply = this.blockingStub.sayHello(req);
        LOGGER.info("[sayHello] req:{}, resp:{}", req, reply);

        this.simpleStub.sayHello(req, new StreamObserver<HelloReply>() {
            @Override
            public void onNext(HelloReply helloReply) {
                LOGGER.info("[sayHello] resp:{}", helloReply);
            }

            @Override
            public void onError(Throwable throwable) {
                LOGGER.error("[sayHello] cause error:", throwable);
            }

            @Override
            public void onCompleted() {
                LOGGER.info("[sayHello] completed");
            }
        });
    }

    public void sayHelloWithServerStream() {
        HelloRequest req = HelloRequest.newBuilder()
                .setName("Jacky")
                .build();

        Iterator<HelloReply> replyIterator = this.blockingStub.sayHelloWithServerStream(req);
        while (replyIterator.hasNext()) {
            HelloReply reply = replyIterator.next();
            LOGGER.info("[sayHelloWithServerStream] blocking resp:{}", reply);
        }

        this.simpleStub.sayHelloWithServerStream(req,
                new StreamObserver<HelloReply>() {
                    @Override
                    public void onNext(HelloReply helloReply) {
                        LOGGER.info("[sayHelloWithServerStream] resp:{}", helloReply);
                    }

                    @Override
                    public void onError(Throwable throwable) {
                        LOGGER.error("[sayHelloWithServerStream] cause error:", throwable);
                    }

                    @Override
                    public void onCompleted() {
                        LOGGER.info("[sayHelloWithServerStream] completed");
                    }
                });
    }

    public void sayHelloWithClientStream() {
        // 仅支付非阻塞式API
        StreamObserver<HelloRequest> requestObserver = this.simpleStub
                .sayHelloWithClientStream(new StreamObserver<HelloReply>() {
                    @Override
                    public void onNext(HelloReply helloReply) {
                        LOGGER.info("[sayHelloWithClientStream] resp:{}", helloReply);
                    }

                    @Override
                    public void onError(Throwable throwable) {
                        LOGGER.error("[sayHelloWithClientStream] cause error:", throwable);
                    }

                    @Override
                    public void onCompleted() {
                        LOGGER.info("[sayHelloWithClientStream] completed");
                    }
                });

        requestObserver.onNext(HelloRequest.newBuilder().setName("Tom").build());
        requestObserver.onNext(HelloRequest.newBuilder().setName("Jerry").build());
        requestObserver.onNext(HelloRequest.newBuilder().setName("Lucy").build());

        requestObserver.onCompleted();
    }


    public void sayHelloBiDirectStream() {
        StreamObserver<HelloRequest> requestObserver = this.simpleStub
                .sayHelloWithClientStream(new StreamObserver<HelloReply>() {
                    @Override
                    public void onNext(HelloReply helloReply) {
                        LOGGER.info("[sayHelloBiDirectStream] resp:{}", helloReply);
                    }

                    @Override
                    public void onError(Throwable throwable) {
                        LOGGER.error("[sayHelloBiDirectStream] cause error:", throwable);
                    }

                    @Override
                    public void onCompleted() {
                        LOGGER.info("[sayHelloBiDirectStream] completed");
                    }
                });

        requestObserver.onNext(HelloRequest.newBuilder().setName("Nancy").build());
        requestObserver.onNext(HelloRequest.newBuilder().setName("Lily").build());
        requestObserver.onNext(HelloRequest.newBuilder().setName("Jan").build());

        requestObserver.onCompleted();
    }
}
